home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 445.lha / RoadRoute_v1.6 / United States / RoadRoute.c < prev    next >
C/C++ Source or Header  |  1990-12-06  |  30KB  |  866 lines

  1. /* after years of fiddling..
  2.   'v1.0  September 89
  3.   'v1.6  (adds printing) August 90
  4. 'Jim Butterfield  */
  5.  
  6.    /* compile with lc -Lcd -v <filename> */
  7. #include <proto/exec.h>
  8. #include <proto/dos.h>
  9. #include <stdio.h>
  10. #define BUFFERLINE 50
  11. #define INFOSIZE sizeof(struct FileInfoBlock)
  12. #define TRAILLEN 100
  13.  
  14. /* File Support structures */
  15. struct CityData {
  16.                 char *CityName;              /* full name  w/state */
  17.                 char *StateName;             /* state/province only */
  18.                 struct CityData *CityLink;   /* init letter chain */
  19.                 struct CityData *StateLink;  /* init letter chain */
  20.                 struct RouteData *RoadList;  /* roads to/from city */
  21.                 struct CityData *WorkList;   /* temp job queue */
  22.                 struct CityData *NextCity[2];  /* result links */
  23.       /* Mindist[0] doubles as CityDupe flag during file input */
  24.                 unsigned short MinDist[2];   /* closest so far */
  25.                 unsigned char StateDupe;     /* one name per state */
  26.                 unsigned char Colum;         /* goes with RoadList */
  27.                 };
  28. struct RouteData {
  29.                  struct CityData *CityNum[2];  /* cities each end */
  30.                  unsigned short Dist[2];       /* distance, time */
  31.                  char *Hiway;                  /* name of Highway */
  32.                  struct RouteData *RLink[2];   /* link for each city */
  33.                  unsigned char Colm[2];        /* goes with RLink */
  34.                  };
  35. struct RouteData *Route0, *Route9;
  36. struct CityData *City0, *City9;
  37. struct CityData *CharLink[0x20];
  38. struct CityData *ChStLink[0x20];
  39. static char InBuff[BUFFERLINE];
  40. static struct CityData *Trail[TRAILLEN][2];
  41. unsigned short TrailPoint[2];
  42. void TimeShow(unsigned short,char *);
  43. int CityMatch(struct CityData *,char *);
  44. unsigned short ParseCities(char *,long);
  45. unsigned short ParseRoutes(char *,long);
  46. struct CityData * AskCity();
  47. void Navigate(struct CityData *,struct CityData *);
  48. void main()
  49.   {
  50.   long fh, lok;
  51.   unsigned short Column, ColStart, ColEnd;
  52.   unsigned short NextCol, NewCol;
  53.   unsigned short AllocCount, errnum;
  54.   unsigned short TrackTrail;
  55.   struct FileInfoBlock *fibb;
  56.   long CitySize, RouteSize;
  57.   char *CityBlox, *RouteBlox, *DataScan, *Active;
  58.   char *StringStart, *FieldStart;
  59.   char *CityPoint, *RoutePoint;
  60.   struct CityData *From, *Dest, *Via, *SearchCity;
  61.   struct CityData *FLink;
  62.   struct RouteData *NextRoute, *NewRoute;
  63.   unsigned short Cities, Roads;
  64.   unsigned short CityPSize, RoutePSize;
  65.   unsigned char Ct0;             /* general character work value */
  66.   static unsigned short Result[2][2];
  67.   static unsigned short tTime, tMiles;
  68.   static char ActCity[]="Cities";
  69.   static char ActRoad[]="Roads";
  70.   for (Ct0=0; Ct0 < 0x20; Ct0++) CharLink[Ct0]= 0;
  71.   for (Ct0=0; Ct0 < 0x20; Ct0++) ChStLink[Ct0]= 0;
  72.  
  73.   AllocCount=0;
  74.   errnum=2;                   /* no memory */
  75.   if ( (long) (fibb = (struct FileInfoBlock *) AllocMem(INFOSIZE,0L))
  76.                                                                 != 0L)
  77.     {
  78.     AllocCount=1;
  79.     errnum=3;                   /* file problems */
  80.     fprintf(stderr,"RoadRoute V1.6  ..   Jim Butterfield\n");
  81.     fprintf(stderr,"   Release version:  1990 08 18\n");
  82.     Cities=0;
  83.     Active=ActCity;
  84.     if ( (lok = Lock("Cities",ACCESS_READ)) != 0L)
  85.       {
  86.       if ( (fh=Examine(lok,fibb)) !=0L)
  87.         {
  88.         CitySize=fibb->fib_Size;
  89.         if ( (long) (CityBlox = AllocMem(CitySize,0L)) != 0L)
  90.       {
  91.           AllocCount=2;
  92.           if ( (fh = Open("Cities",MODE_OLDFILE)) != 0L)
  93.             {
  94.             errnum=0;
  95.             Read(fh,CityBlox,CitySize);
  96.             Close(fh);
  97.         }                      /* City file opened   */
  98.           }                        /* data alloc OK */
  99.     }                          /* examine OK    */
  100.         UnLock(lok);
  101.       }                            /* lock OK          */
  102.     }                              /* examine alloc OK */
  103.   if (errnum == 0)
  104.     {
  105.     for (DataScan=CityBlox;DataScan < CityBlox+CitySize;DataScan++)
  106.       if (*DataScan == 0x0A) Cities++;
  107.     CityPSize=Cities*sizeof(struct CityData);
  108.     if ( (long) (CityPoint = AllocMem(CityPSize,0L)) != 0L)
  109.       AllocCount=3;
  110.     else
  111.       errnum=2;
  112.     }
  113.   if (errnum ==0 )
  114.     {
  115.     errnum=3;                   /* file problems */
  116.     Active=ActRoad;
  117.     Roads=0;
  118.     if ( (lok = Lock("Roads",ACCESS_READ)) != 0L)
  119.       {
  120.       if ( (fh=Examine(lok,fibb)) !=0L)
  121.         {
  122.         RouteSize=fibb->fib_Size;
  123.         if ( (long) (RouteBlox = AllocMem(RouteSize,0L)) != 0L)
  124.           {
  125.           AllocCount=4;
  126.           if ( (fh = Open("Roads",MODE_OLDFILE)) != 0L)
  127.             {
  128.             errnum=0;
  129.             Read(fh,RouteBlox,RouteSize);
  130.             Close(fh);
  131.             }                      /* file opened   */
  132.           }                        /* data alloc OK */
  133.         }                          /* examine OK    */
  134.       UnLock(lok);
  135.       }                            /* lock OK          */
  136.     }
  137.   if (errnum == 0)
  138.     {
  139.     for (DataScan=RouteBlox;DataScan < RouteBlox+RouteSize;DataScan++)
  140.       if (*DataScan == 0x0A) Roads++;
  141.     RoutePSize=Roads*sizeof(struct RouteData);
  142.     if ( (long) (RoutePoint = AllocMem(RoutePSize,0L)) != 0L)
  143.       AllocCount=5;
  144.     else
  145.       errnum=2;
  146.     }
  147.   if (errnum == 0)
  148.     {
  149.     Active=ActCity;
  150.     fprintf(stderr,">> %d Cities\n",Cities);
  151.     City0 = (struct CityData *) CityPoint;
  152.     errnum=ParseCities(CityBlox,CitySize);
  153.     }
  154.   if (errnum == 0)
  155.     {
  156.     Active=ActRoad;
  157.     fprintf(stderr,">> %d Roads\n",Roads);
  158.     Route0 = (struct RouteData *) RoutePoint;
  159.     errnum=ParseRoutes(RouteBlox,RouteSize);
  160.     }
  161.   switch (errnum)
  162.     {
  163.     case 0:                /* no errors, do main job */
  164.       Ct0='Y';
  165.       while (Ct0 == 'Y')
  166.         {
  167.         long pFlag; 
  168.         FILE *pHandl;
  169.         TrailPoint[0]=0;
  170.         TrailPoint[1]=0;
  171.         fprintf(stderr,"City from: ");
  172.         if (gets(InBuff) == 0 || *InBuff =='\0')  From=City0;
  173.                       else      From=AskCity();
  174.         fprintf(stderr,"From %s to: ",From->CityName);
  175.         if (gets(InBuff) == 0)
  176.           {
  177.           InBuff[0]='?';
  178.           InBuff[1]='\0';
  179.           }
  180.         Dest=AskCity();
  181.         fprintf(stderr,"%s->%s via (or RETURN):  ",
  182.                                   From->CityName,Dest->CityName);
  183.         Via=0;
  184.         if (gets(InBuff) != 0 && *InBuff != '\0')
  185.           {
  186.           Via = AskCity();
  187.           fprintf(stderr,"\n%s->%s via %s\n",
  188.                   From->CityName,Dest->CityName,Via->CityName);
  189.           Navigate(From,Via);
  190.           Navigate(Via,Dest);
  191.           }
  192.         else
  193.           {
  194.           fprintf(stderr,"\n%s->%s DIRECT\n",From->CityName,Dest->CityName);
  195.           Navigate(From,Dest);
  196.           }
  197.         for (Column=0; Column<2; Column++)
  198.           {
  199.           Result[0][Column]=0;   /* dist */
  200.           Result[1][Column]=0;   /* time */
  201.           SearchCity=From;
  202.           for (TrackTrail=0; TrackTrail <TrailPoint[Column]; TrackTrail++)
  203.             {
  204.             FLink=Trail[TrackTrail][Column];
  205.             NextRoute=SearchCity->RoadList;
  206.             NextCol=SearchCity->Colum;
  207.             while (NextRoute !=0 &&
  208.                    FLink != NextRoute->CityNum[1-NextCol]) 
  209.               {
  210.               NewRoute=NextRoute->RLink[NextCol];
  211.               NewCol=NextRoute->Colm[NextCol];
  212.               NextRoute=NewRoute;
  213.               NextCol=NewCol;
  214.               }
  215.             Result[1][Column]=Result[1][Column]+NextRoute->Dist[1];
  216.             Result[0][Column]=Result[0][Column]+NextRoute->Dist[0];
  217.             SearchCity=FLink;
  218.             }  /* next Link */
  219.           }    /* next Column */
  220.         ColStart=0;
  221.         ColEnd=1;
  222.         if (Result[0][0]==Result[0][1])
  223.           {
  224.           ColStart=1;
  225.           ColEnd=1;
  226.           }
  227.         if (Result[1][0]==Result[1][1])
  228.           {
  229.           ColStart=0;
  230.           ColEnd=0;
  231.           }
  232.         for (Column=ColStart; Column<=ColEnd; Column++)
  233.           {
  234.           fprintf(stderr,"%4d Miles, time: ",Result[0][Column]);
  235.           TimeShow(Result[1][Column],InBuff);
  236.           fprintf(stderr,"%s\n",InBuff);
  237.           } /* next Column */
  238.         if (ColStart != ColEnd)
  239.           fprintf(stderr,"FASTEST, SHORTEST (or BOTH)\n");
  240.         else
  241.           fprintf(stderr,"Press RETURN to continue\n");
  242.         fprintf(stderr," .. or P to print ");
  243.         pHandl=stdout;
  244.         pFlag=0;
  245.         Ct0='B';
  246.         if ((StringStart=gets(InBuff)) != 0) Ct0=*StringStart;
  247.         if (Ct0 > 'Z') Ct0 -=32;
  248.         if (Ct0 =='P')
  249.           {
  250.           pFlag=1;
  251.           Ct0='B';
  252.       pHandl=fopen("prt:","w");
  253.           }      
  254.         if (Ct0 =='S') ColEnd=0;
  255.         if (Ct0 =='F') ColStart=1;
  256.         for (Column=ColStart; Column<=ColEnd; Column++)
  257.           {
  258.           fprintf(pHandl,"From: %s\nTo: %s\n",From->CityName,Dest->CityName);
  259.           if (Via != 0) fprintf (pHandl,"Via: %s\n",Via->CityName);
  260.           tMiles=0;
  261.           tTime=0;
  262.           SearchCity=From;
  263.           for (TrackTrail=0; TrackTrail <TrailPoint[Column]; TrackTrail++)
  264.             {
  265.             FLink=Trail[TrackTrail][Column];
  266.             NextRoute=SearchCity->RoadList;
  267.             NextCol=SearchCity->Colum;
  268.             while (NextRoute > 0 && 
  269.                    FLink!=NextRoute->CityNum[1-NextCol]) 
  270.               {
  271.               NewRoute=NextRoute->RLink[NextCol];
  272.               NewCol=NextRoute->Colm[NextCol];
  273.               NextRoute=NewRoute;
  274.               NextCol=NewCol;
  275.               }   /* wend, no NextRoute */
  276.             tTime=tTime+NextRoute->Dist[1];
  277.             tMiles=tMiles+NextRoute->Dist[0];
  278.             TimeShow(NextRoute->Dist[1],InBuff);
  279.             /*  Print highway link information */
  280.             fprintf(pHandl,"%4d %s ",NextRoute->Dist[0],InBuff);
  281.             StringStart=InBuff;
  282.             FieldStart=SearchCity->CityName;
  283.             while (*FieldStart != ',')
  284.               *StringStart++ =*FieldStart++;
  285.             *StringStart++ =' ';
  286.             *StringStart++ ='-';
  287.             *StringStart++ =' ';
  288.             FieldStart=FLink->CityName;
  289.             while (*FieldStart != ',')
  290.               *StringStart++ =*FieldStart++;
  291.             *StringStart++ =0;
  292.             fprintf(pHandl,"%s via %s\n",InBuff,NextRoute->Hiway);
  293.             SearchCity=FLink;
  294.             }  /* next link */
  295.           fprintf(pHandl,"     Total Miles: %d\n",tMiles);
  296.           TimeShow(tTime,InBuff);
  297.           fprintf(pHandl,"     Driving Time: %s\n",InBuff);
  298.           }  /* next Column */
  299.         if (pFlag==1)
  300.           {
  301.           fprintf(pHandl,"\f");
  302.           fclose(pHandl);
  303.           }
  304.         Ct0='N';
  305.         fprintf (stderr,"Another trip? ");
  306.         if ((StringStart=gets(InBuff)) != 0) Ct0=*StringStart;
  307.         if (Ct0 > 'Z') Ct0 -=32;
  308.         }           /* another trip */
  309.       break;
  310.     case 1:         /* trouble in file data */
  311.       fprintf(stderr,"----> Correct data in file %s and try again.\n",Active);
  312.       break;
  313.     case 2:         /* AllocMem refused */
  314.         fprintf(stderr,"----> Not enough memory to run RoadRoute.\n");
  315.     break;
  316.     case 3:         /* real trouble with file */
  317.         fprintf(stderr,"----> Can't proceed due to unreadable file %s.\n",Active);
  318.         break;
  319.     default:
  320.       fprintf(stderr,"System error: %d\n",errnum);
  321.     }  /* error switch area */
  322.   switch (AllocCount)
  323.     {
  324.     case 5:  FreeMem(RoutePoint,RoutePSize);
  325.     case 4:  FreeMem( (char *) RouteBlox,RouteSize);
  326.     case 3:  FreeMem(CityPoint,CityPSize);
  327.     case 2:  FreeMem( (char *) CityBlox,CitySize);
  328.     case 1:  FreeMem( (char *) fibb,INFOSIZE);
  329.     }  /* memory cleanup */
  330.   if (errnum != 0)
  331.     {
  332.     fprintf(stderr,"Press any key to quit\n");
  333.     gets(InBuff);
  334.     }    
  335.   }
  336.  
  337.  
  338. void TimeShow(Time, Buffer)
  339.   unsigned short Time;
  340.   char *Buffer;
  341.   {
  342.   unsigned short MinFlag, radix, digit, SuppressLimit, FillChar, Hours[2];
  343.   Hours[0]=Time/60;
  344.   Hours[1]=Time%60;
  345.   SuppressLimit=1;
  346.   FillChar=':';
  347.   radix=10000;
  348.   while (radix>Hours[0] && radix>SuppressLimit)
  349.     {
  350.     radix/=10;
  351.     *Buffer++ =' ';
  352.     }
  353.   for (MinFlag=0;MinFlag<2;MinFlag++)
  354.     {
  355.     while (radix>0)
  356.       {
  357.       digit=Hours[MinFlag]/radix;
  358.       Hours[MinFlag]%=radix;
  359.       *Buffer++ =digit+'0';
  360.       radix/=10;
  361.       }  /* more digits */
  362.     *Buffer++ =FillChar;
  363.     FillChar=0;
  364.     SuppressLimit=10;
  365.     radix=10;
  366.     }  /* next MinFlag */
  367.   }
  368.  
  369. int CityMatch(TabPoint,CityText)
  370.   struct CityData *TabPoint;
  371.   char *CityText;
  372.   {
  373.   /* Name must match exactly; state is optional */
  374.   int Match, StateMatch;
  375.   char TablChar, TextChar;
  376.   char *TableName;
  377.   TableName=TabPoint->CityName;
  378.   TablChar=*TableName++; if (TablChar > 'Z') TablChar-=0x20;
  379.   TextChar=*CityText++; if (TextChar > 'Z') TextChar-=0x20;
  380.   Match=1;
  381.   StateMatch=0;
  382.   while (Match == 1 && TextChar != ',')
  383.     {
  384.     if (TablChar != TextChar)
  385.       {
  386.       if (TablChar ==',' && TextChar =='/') StateMatch=1;
  387.       else Match=0;
  388.       }
  389.     TablChar=*TableName++; if (TablChar > 'Z') TablChar-=0x20;
  390.     TextChar=*CityText++; if (TextChar > 'Z') TextChar-=0x20;
  391.     }
  392.   if (Match==1)
  393.     {
  394.     if (TablChar != 0 && TablChar !=',') Match=0;
  395.     if (TabPoint->MinDist[0]==1 && StateMatch ==0) Match=0;
  396.     }
  397.   return (Match);
  398.   }
  399.  
  400. unsigned short ParseCities(CitiesBlock,CBlockSize)
  401.   char *CitiesBlock;
  402.   long CBlockSize;
  403.   {
  404.   struct CityData *CityStruct, *CityScan;
  405.   char *LineBegin, *EndLine, *NewName, *OldName;
  406.   unsigned short CityError;
  407.   unsigned char CityIndex,NewChar,OldChar;
  408.   unsigned char FoundFlag, StateFlag;
  409.   CityError=0;
  410.   CityStruct = City0;
  411.   LineBegin = CitiesBlock;
  412.   FoundFlag=0;
  413.   for (EndLine=CitiesBlock;EndLine < CitiesBlock+CBlockSize;EndLine++)
  414.   if (*EndLine == ',' || *EndLine == 0x0A)
  415.     {
  416.     if (*EndLine == ',')
  417.       {
  418.       FoundFlag=1;
  419.       CityStruct->CityName=LineBegin;
  420.       /* MinDist[0] used as temporary dupe CityName flag */
  421.       CityStruct->MinDist[0]=0;          /* No City Duplicate Name */
  422.       CityIndex = *LineBegin & 0x1F;        /* strip first char */
  423.       CityScan = CharLink[CityIndex];
  424.       while (CityScan != 0)
  425.         {
  426.         NewName=LineBegin;
  427.         OldName=CityScan->CityName;
  428.         NewChar=*NewName++; if (NewChar > 0x60) NewChar -= 0x20;
  429.         OldChar=*OldName++; if (OldChar > 0x60) OldChar -= 0x20;
  430.         while (NewChar == OldChar && NewChar != ',')
  431.           {
  432.           NewChar=*NewName++; if (NewChar > 0x60) NewChar -= 0x20;
  433.           OldChar=*OldName++; if (OldChar > 0x60) OldChar -= 0x20;
  434.           }
  435.         if (NewChar == OldChar)     /* Dupe City Name */
  436.           {
  437.           CityStruct->MinDist[0]=1;
  438.           CityScan->MinDist[0]=1;
  439.           }
  440.         CityScan = CityScan->CityLink;
  441.         }   /* chain search for input city name */
  442.        CityStruct->CityLink = CharLink[CityIndex];
  443.       CityStruct->RoadList = 0;
  444.       CharLink[CityIndex]=CityStruct;
  445.       LineBegin=EndLine+1;
  446.       }    /* end of comma..City parsing */
  447.     else     /* NewLine */
  448.       {
  449.       *EndLine=0;
  450.       if (FoundFlag ==0)
  451.         {
  452.         fprintf(stderr,"*FILE Cities: NO COMMA:\n%s\n",LineBegin);
  453.         CityError=1;
  454.         }
  455.       FoundFlag=0;
  456.       CityStruct->StateName=LineBegin;
  457.       CityStruct->StateDupe=1;
  458.       CityIndex = *LineBegin & 0x1F;        /* strip first char */
  459.       CityScan = ChStLink[CityIndex];
  460.       StateFlag = 0;
  461.       while (CityScan != 0 && StateFlag == 0)
  462.         {
  463.         NewName=LineBegin;
  464.         OldName=CityScan->StateName;
  465.         NewChar=*NewName++; if (NewChar > 0x60) NewChar -= 0x20;
  466.         OldChar=*OldName++; if (OldChar > 0x60) OldChar -= 0x20;
  467.         while (NewChar == OldChar && NewChar !=0 && OldChar !=0)
  468.           {
  469.           NewChar=*NewName++; if (NewChar > 0x60) NewChar -= 0x20;
  470.           OldChar=*OldName++; if (OldChar > 0x60) OldChar -= 0x20;
  471.           }
  472.         if (NewChar == OldChar)
  473.           {
  474.           CityScan->StateDupe=0;
  475.           StateFlag=1;
  476.           }
  477.         CityScan = CityScan->StateLink;
  478.         }   /* more states in chain */
  479.       CityStruct->StateLink = ChStLink[CityIndex];
  480.       ChStLink[CityIndex]=CityStruct;
  481.       CityStruct++;
  482.       LineBegin=EndLine+1;
  483.       }    /* end of NewLine parsing */
  484.     }
  485.   City9=CityStruct;
  486.   return(CityError);
  487.   }
  488.  
  489. unsigned short ParseRoutes(DataBlock,BlockSize)
  490.   char *DataBlock;
  491.   long BlockSize;
  492.   {
  493.   struct RouteData *RouteStruct;
  494.   struct CityData *CityScan, *FoundCity;
  495.   unsigned short ErrorFlag, CityColm, CityFlag, CityValue, Multiplier;
  496.   unsigned char CtNameKey, Digit;
  497.   char *LineStart,*LineEnd,*FieldStart,*FieldEnd,*NumPtr;
  498.   ErrorFlag=0;
  499.   RouteStruct = Route0;
  500.   LineStart = DataBlock;
  501.   for (LineEnd=DataBlock;LineEnd < DataBlock+BlockSize;LineEnd++)
  502.   if (*LineEnd == 0x0A)
  503.     {
  504.     *LineEnd=0;
  505.     FieldStart=LineStart;
  506.     for (CityColm=0 ; ErrorFlag==0 && CityColm < 2 ; CityColm++)
  507.       {
  508.       for (FieldEnd=FieldStart ;
  509.              *FieldEnd !=',' && FieldEnd < LineEnd ; FieldEnd++);
  510.       if (*FieldEnd !=',')
  511.         {
  512.         fprintf(stderr,"*FILE Roads:  MISSING FIELDS:\n%s\n",LineStart);
  513.         ErrorFlag=1;
  514.         }   /* no comma! */
  515.       /* ***** search city name chain */
  516.       CtNameKey = *FieldStart & 0x1F;        /* strip first char */
  517.       CityScan = CharLink[CtNameKey];
  518.       CityValue =0;
  519.       while (CityScan != 0 && CityValue ==0)
  520.         {
  521.         if (CityMatch(CityScan,FieldStart)==1)
  522.           {
  523.           CityValue=1;
  524.           FoundCity=CityScan;
  525.           }
  526.         CityScan = CityScan->CityLink;
  527.         }   /* chain search for input city name */      
  528.       if (CityValue ==0)
  529.         {
  530.         fprintf(stderr,"*FILE Roads:  CITY NOT FOUND:\n%s\n",LineStart);
  531.         ErrorFlag=1;
  532.         }
  533.       RouteStruct->CityNum[CityColm]=FoundCity;
  534.       RouteStruct->RLink[CityColm]=FoundCity->RoadList;
  535.       RouteStruct->Colm[CityColm]=FoundCity->Colum;
  536.       FoundCity->RoadList=RouteStruct;
  537.       FoundCity->Colum=CityColm;
  538.       FieldStart=FieldEnd+1;
  539.       }   /* two-city loop */
  540.     /* Now grab mileage, time, and Hiway */
  541.     for (CityColm=0 ; ErrorFlag==0 && CityColm < 2 ; CityColm++)
  542.       {
  543.       for (FieldEnd=FieldStart ;
  544.                 *FieldEnd !=',' && FieldEnd < LineEnd ; FieldEnd++);
  545.       if (*FieldEnd !=',')
  546.         {
  547.         fprintf(stderr,"FILE Roads:  MISSING FIELDS:\n%s????\n",LineStart);
  548.         ErrorFlag=1;
  549.         }   /* no comma! */
  550.       CityValue=0 ; CityFlag=0;
  551.       Multiplier=10;
  552.       for (NumPtr=FieldStart ; CityFlag==0 && NumPtr < FieldEnd ;
  553.                                                           NumPtr++)
  554.         {
  555.         Digit=*NumPtr;
  556.         if (Digit >='0' && Digit<='9')
  557.           {
  558.           CityValue=CityValue * Multiplier + Digit - '0';
  559.           Multiplier=10;
  560.           }
  561.         else if (Digit ==':') Multiplier = 6;
  562.         }  /* Scan for colon */
  563.       RouteStruct->Dist[CityColm]=CityValue;
  564.       FieldStart=FieldEnd+1;
  565.       }    /* Two value paramemters */
  566.     RouteStruct->Hiway=FieldStart;
  567.     RouteStruct++;
  568.     LineStart=LineEnd+1;
  569.     }    /* end of routefile scan */
  570.   Route9 = RouteStruct;
  571.   return(ErrorFlag);
  572.   }   /* if no error, table build */
  573.  
  574. #define MENUSIZE 15
  575. struct CityData * AskCity()
  576.   {
  577.   char *InputString, *InputName, *TableName;
  578.   unsigned char MulKey, CityKey, InChar, CityChar, StateFlag;
  579.   struct CityData *CityStruct, *CityPStruct;
  580.   unsigned short MenuPointer, MenuList;
  581.   static struct CityData *Menu[MENUSIZE];
  582.  
  583.   InputString=InBuff;
  584.   CityKey = *InputString & 0x1F;        /* strip first char */
  585.   CityStruct = CharLink[CityKey];
  586.   MulKey = 0;              /* Single menu */
  587.   CityPStruct = 0;
  588.   MenuPointer = 0;
  589.   while (CityStruct != 0)
  590.     {
  591.     MenuPointer = 0;
  592.     while ( CityStruct !=0 && MenuPointer < MENUSIZE )
  593.       {
  594.       InputName=InputString;
  595.       TableName=CityStruct->CityName;
  596.       InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  597.       CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  598.       while (InChar == CityChar && InChar != 0)
  599.         {
  600.         InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  601.         CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  602.         }
  603.       if (InChar == 0)
  604.         {
  605.         Menu[MenuPointer++]=CityStruct;
  606.         CityPStruct = CityStruct;
  607.         }
  608.       CityStruct = CityStruct->CityLink;
  609.       }   /* chain search for input city name */
  610.     if ( MenuPointer > 1)
  611.       {
  612.       for (MenuList=0;MenuList < MenuPointer;MenuList++)
  613.         fprintf(stderr,"%d: %s\n",MenuList+1,Menu[MenuList]->CityName);
  614.       fprintf(stderr,">>> Pick 1 to %d:",MenuPointer);
  615.       if (CityStruct != 0)
  616.         {
  617.         fprintf(stderr," or RETURN for more:");
  618.         CityStruct = CityPStruct;
  619.     MulKey=1;           /* Multiple menus */
  620.         }
  621.       else if ( MulKey != 0 )
  622.         {
  623.         fprintf(stderr," or RETURN to restart list:");
  624.         CityStruct = CharLink[CityKey]; /* return to first menu */
  625.         }
  626.       StateFlag=0;
  627.       if ((InputString=gets(InBuff)) != 0)
  628.         {
  629.         InChar=*InputString++;
  630.         while (InChar != 0)
  631.           {
  632.           if (InChar >='0' && InChar<='9')
  633.                   StateFlag=StateFlag * 10 + InChar - '0';
  634.           InChar=*InputString++;
  635.           }
  636.         }     /* endif, not RETURN */
  637.       if (StateFlag < 1 || StateFlag > MenuPointer) StateFlag=1;
  638.         else  CityStruct = 0;
  639.       CityPStruct=Menu[StateFlag-1];      
  640.       }  /* endif cities to pick from */
  641.     }   /* while more cities in list */
  642.   switch (MenuPointer)
  643.     {
  644.     case 0:            /* No city match */
  645.       fprintf(stderr,"Province or State: ");
  646.       if ((InputString=gets(InBuff)) == 0) InputString=City0->CityName;
  647.       /* Search for state as input */
  648.       MenuPointer = 0;
  649.       Menu[MenuPointer]=City0;
  650.       CityKey = *InputString & 0x1F;    /* strip state first char */
  651.       CityStruct = ChStLink[CityKey];
  652.       if (CityStruct == 0) CityStruct = City0;
  653.       while (CityStruct != 0)
  654.         {
  655.         if (CityStruct->StateDupe == 1)   /* one flag set per state*/
  656.           {
  657.           InputName=InputString;
  658.           TableName=CityStruct->StateName;
  659.           InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  660.           CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  661.           while (InChar == CityChar && InChar != 0)
  662.             {
  663.             InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  664.             CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  665.             }
  666.           if (InChar == 0)
  667.             if (MenuPointer < MENUSIZE) Menu[MenuPointer++]=CityStruct;
  668.           }
  669.         CityStruct = CityStruct->StateLink;
  670.         }   /* more states in chain */
  671.       if (MenuPointer == 0)    /* search for first letter state */
  672.         {
  673.         CityStruct = ChStLink[CityKey];
  674.         if (CityStruct == 0) CityStruct = City0;
  675.         while (CityStruct != 0)
  676.           {
  677.           if (CityStruct->StateDupe == 1)
  678.             {
  679.             InputName=InputString;
  680.             TableName=CityStruct->StateName;
  681.             InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  682.             CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  683.             if (InChar == CityChar)
  684.               if (MenuPointer < MENUSIZE) Menu[MenuPointer++]=CityStruct;
  685.             }
  686.           CityStruct = CityStruct->StateLink;
  687.           }   /* while more states in alpha chain */
  688.         }  /* endif, single char state search */
  689.       if (MenuPointer > 1)
  690.         {
  691.         for (MenuList=0;MenuList < MenuPointer;MenuList++)
  692.           fprintf(stderr,"%d: %s\n",MenuList+1,Menu[MenuList]->StateName);
  693.         fprintf(stderr,">>> Pick 1 to %d:",MenuPointer);
  694.         StateFlag=0;
  695.         if ((InputString=gets(InBuff)) != 0)
  696.           {
  697.           InChar=*InputString++;
  698.           while (InChar != 0)
  699.             {
  700.             if (InChar >='0' && InChar<='9')
  701.               StateFlag=StateFlag * 10 + InChar - '0';
  702.             InChar=*InputString++;
  703.             }
  704.           if (StateFlag<1 || StateFlag>MenuPointer) StateFlag=1;
  705.           StateFlag -=1;
  706.           }
  707.         CityStruct=Menu[StateFlag];
  708.         }  /* endif, pick state from list */
  709.       if (MenuPointer == 0) CityStruct=City0;
  710.       if (MenuPointer == 1) CityStruct=Menu[0];
  711.       /* Now track cities within a given state */
  712.       InputString=CityStruct->StateName;
  713.       CityKey = *InputString & 0x1F;        /* strip first char */
  714.         /* Track the state alpha list */
  715.       MulKey=0;             /* not multiple menu */
  716.       CityStruct = ChStLink[CityKey];
  717.       CityPStruct = 0;
  718.       MenuPointer = 0;
  719.       while (CityStruct != 0)  /* search cities in a state */
  720.         {
  721.         MenuPointer = 0;
  722.         while ( CityStruct != 0  && MenuPointer < MENUSIZE )
  723.           {
  724.           InputName=InputString;
  725.           TableName=CityStruct->StateName;
  726.           InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  727.           CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  728.           while (InChar == CityChar && InChar != 0)
  729.             {
  730.             InChar=*InputName++; if (InChar > 0x60) InChar -= 0x20;
  731.             CityChar=*TableName++; if (CityChar > 0x60) CityChar -= 0x20;
  732.             }
  733.           if (InChar == CityChar)
  734.         {
  735.             Menu[MenuPointer++]=CityStruct;
  736.             CityPStruct = CityStruct;
  737.             }
  738.           CityStruct = CityStruct->StateLink;
  739.           }   /* while more cities and space in menu */
  740.         if (MenuPointer > 1)
  741.           {
  742.           for (MenuList=0;MenuList < MenuPointer;MenuList++)
  743.             fprintf(stderr,"%d: %s\n",MenuList+1,Menu[MenuList]->CityName);
  744.           fprintf(stderr,">>> Pick 1 to %d:",MenuPointer);
  745.           if (CityStruct != 0)
  746.             {
  747.             fprintf(stderr," or RETURN for more:");
  748.             MulKey=1;      /* multiple menus */
  749.             CityStruct = CityPStruct;
  750.             }
  751.           else if ( MulKey != 0 )
  752.             {
  753.             fprintf(stderr," or RETURN for to restart list:");
  754.             CityStruct = ChStLink[CityKey]; /* back to first menu */
  755.             }
  756.           StateFlag=0;
  757.           if ((InputName=gets(InBuff)) != 0)
  758.             {
  759.             InChar=*InputName++;
  760.             while (InChar != 0)
  761.               {
  762.               if (InChar >='0' && InChar<='9')
  763.                 StateFlag=StateFlag * 10 + InChar - '0';
  764.               InChar=*InputName++;
  765.               }  /* while more numeric string */
  766.             }  /* endif, non-RETURN */
  767.           }              /* endif, pick city within state */
  768.         if (StateFlag < 1 || StateFlag > MenuPointer) StateFlag =1;
  769.           else  CityStruct = 0;
  770.         CityPStruct=Menu[StateFlag-1];
  771.         }     /* while more cities in state list */
  772.       if (MenuPointer == 0) CityPStruct=City0;
  773.       if (MenuPointer == 1) CityPStruct=Menu[0]; 
  774.       break;
  775.     case 1:             /* unique input city match */
  776.       CityPStruct = Menu[0];
  777.     }    /* endswitch, unique or no match */
  778.   return(CityPStruct);
  779.   }
  780.  
  781. void Navigate(struct CityData *Start,struct CityData *Finish)
  782.   {
  783.   unsigned short Column, Travel;
  784.   unsigned short NextCol, NewCol;
  785.   struct CityData *CityScan;
  786.   struct CityData *BLink, *SearchCity;
  787.   struct CityData *ELink, *FLink, *OtherCity;
  788.   struct RouteData *NextRoute, *NewRoute;
  789.   static unsigned short MiniVal;
  790.   static unsigned short ThisDist[2];
  791.         for (CityScan=City0; CityScan<City9; CityScan++)
  792.           {
  793.           CityScan->WorkList = 0;
  794.           for (Column=0; Column<2; Column++)
  795.             {
  796.             CityScan->MinDist[Column]=9999;
  797.             CityScan->NextCity[Column]=0;
  798.             }
  799.           }
  800.         ELink=Finish;
  801.         MiniVal=0;
  802.         for (Column=0; Column<2; Column++)
  803.           {
  804.           Finish->MinDist[Column]=0;
  805.           ThisDist[Column]=9999;
  806.           }
  807.         SearchCity=Finish;       
  808.         while (SearchCity != 0)
  809.           {
  810.           for (Column=0; Column<2; Column++)
  811.             {
  812.             if (SearchCity->MinDist[Column] < Start->MinDist[Column])
  813.               {
  814.     /*   if (Column==0)
  815.      *   printf("Scanning map at range: %d\n",SearchCity->MinDist[0]); */
  816.             MiniVal=SearchCity->MinDist[Column];
  817.             NextRoute=SearchCity->RoadList;
  818.             NextCol=SearchCity->Colum;
  819.             while (NextRoute != 0)
  820.                 {
  821.                 OtherCity=NextRoute->CityNum[1-NextCol];
  822.                 Travel=MiniVal+NextRoute->Dist[Column];
  823.                 if (OtherCity->MinDist[Column] > Travel)
  824.                   /* found a new shortest path */
  825.                   {
  826.                   OtherCity->MinDist[Column]=Travel;
  827.                   OtherCity->NextCity[Column]=SearchCity;
  828.                   if (OtherCity->WorkList == 0 && ELink!=OtherCity)
  829.                     {
  830.                     BLink=SearchCity;
  831.                     FLink=SearchCity->WorkList;
  832.                     while (FLink!=0 && Travel>FLink->MinDist[Column])
  833.                       {
  834.                       BLink=FLink;
  835.                       FLink=BLink->WorkList;
  836.                       }
  837.                     BLink->WorkList=OtherCity;
  838.                     OtherCity->WorkList=FLink;
  839.                     if (FLink==0) ELink=OtherCity;
  840.                     }  /* build new Worklist */
  841.                   }    /* shorter total distance */
  842.                 if (Travel < ThisDist[Column]) ThisDist[Column]=Travel; 
  843.                 NewRoute=NextRoute->RLink[NextCol];
  844.                 NewCol=NextRoute->Colm[NextCol];
  845.                 NextRoute=NewRoute;
  846.                 NextCol=NewCol;
  847.                 }   /* Try another route from SearchCity */
  848.               }     /* City within target range */
  849.             }       /* Next Column */
  850.           BLink=SearchCity->WorkList;
  851.           SearchCity->WorkList=0;
  852.           SearchCity=BLink;
  853.           }  /* if SearchCity not zero, go back */
  854.         for (Column=0; Column<2; Column++)
  855.           {
  856.           SearchCity=Start;
  857.           FLink=SearchCity->NextCity[Column];
  858.           while (FLink != 0)
  859.             {
  860.             if (TrailPoint[Column]<TRAILLEN)
  861.            Trail[TrailPoint[Column]++][Column]=FLink;
  862.             SearchCity=FLink;
  863.             FLink=SearchCity->NextCity[Column];
  864.             }  /* wend for next FLink */
  865.           }    /* next Column */
  866.   }